﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Xml;
using TimeMachine.Engine.Metrics;
using System.Linq;

namespace TimeMachine.Engine.Storing.Impl
{
	public class XmlMetricsLoader : IMetricsLoader
	{
		private readonly IMetricValuesStorageDisposition metricsStorageDisposition;

		public XmlMetricsLoader(IMetricValuesStorageDisposition metricsStorageDisposition)
		{
			this.metricsStorageDisposition = metricsStorageDisposition;
		}

		public MetricValue[] Load(string metricId)
		{
			string filename = metricsStorageDisposition.GetMetricsFilename(metricId);
			if (File.Exists(filename))
			{
				using (var stream = new FileStream(filename, FileMode.Open))
				using (XmlReader reader = XmlReader.Create(stream))
					return ReadCollection(
						reader, "commit",
						() => ReadCommit(metricId, reader)).ToArray(); // если убрать ToArray будет выстрел в ногу чтением из закрытого stream-а
			}
			return new MetricValue[0];
		}

		public IEnumerable<string> KnownMetricIds()
		{
			return metricsStorageDisposition.GetMetricsIds();
		}

		private static IEnumerable<TItem> ReadCollection<TItem>(
			XmlReader reader,
			string itemElementName,
			Func<TItem> read)
		{
			reader.MoveToElement();
			bool hasMoreItems = reader.ReadToDescendant(itemElementName);
			while (hasMoreItems)
			{
				yield return read();
				hasMoreItems = reader.ReadToNextSibling(itemElementName);
			}
		}

		private static MetricValue ReadCommit(string metricId, XmlReader reader)
		{
			int rev = int.Parse(ReadAttribute(reader, "rev"));
			double value = double.Parse(ReadAttribute(reader, "value"), NumberFormatInfo.InvariantInfo);
			return new MetricValue(rev, metricId, value);
		}

		private static string ReadAttribute(XmlReader reader, string attributeName)
		{
			return !reader.MoveToAttribute(attributeName) ? null : reader.Value;
		}
	}
}